package com.lijiajia.cloud.resource.common.web.servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lijiajia.cloud.common.core.rest.RestResult;
import com.lijiajia.cloud.common.core.rest.Result;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * rest接口返回值处理器
 *
 * @author lijiajia
 * @since 2019-04-05
 */
public class RestReturnHandler implements HandlerMethodReturnValueHandler, BeanPostProcessor {
    private List<ResponseBodyAdvice<Object>> advices = new ArrayList<>();

    private ObjectMapper objectMapper = new ObjectMapper();

    public RestReturnHandler() {
    }

    public RestReturnHandler(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public boolean supportsReturnType(MethodParameter methodParameter) {
        return methodParameter.getMethodAnnotation(RestResult.class) != null;
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        mavContainer.setRequestHandled(true);

        /*RestResult restResult = returnType.getMethodAnnotation(RestResult.class);*/
        HttpServletResponse response = Objects.requireNonNull(webRequest.getNativeResponse(HttpServletResponse.class));
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        String json = objectMapper.writeValueAsString(Result.success(returnValue));
        response.getWriter().write(json);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ResponseBodyAdvice) {
            advices.add((ResponseBodyAdvice<Object>) bean);
        } else if (bean instanceof RequestMappingHandlerAdapter) {
            List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(Objects.requireNonNull(((RequestMappingHandlerAdapter) bean).getReturnValueHandlers()));

            HandlerMethodReturnValueHandler jsonHandler = handlers.stream()
                    .filter(handler -> handler instanceof RestReturnHandler)
                    .findFirst().orElse(null);

            if (jsonHandler != null) {
                handlers.remove(jsonHandler);
                handlers.add(0, jsonHandler);
                ((RequestMappingHandlerAdapter) bean).setReturnValueHandlers(handlers);
            }
        }
        return bean;
    }
}
